﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AutoUpdateMgr.Client
{
    using System.Net;
    using System.Net.Sockets;
    using DotNetty.Buffers;
    using DotNetty.Codecs;
    using DotNetty.Handlers.Logging;
    using DotNetty.Transport.Bootstrapping;
    using DotNetty.Transport.Channels;
    using DotNetty.Transport.Channels.Sockets;
    using DotNetty.Handlers.Timeout;
    using System.Threading.Tasks;
    public class Client
    {
        private MultithreadEventLoopGroup group { set; get; } = null;

        private IChannel clientChannel { set; get; } = null;

        private Bootstrap bootstrap { set; get; } = null;

        private string serverHost { set; get; } = "";

        private int serverPort { set; get; } = 3143;

        private int connectRetry { set; get; } = 3;

        public async void connectAsync(string serverHost, int serverPort)
        {
            try
            {
                this.serverHost = serverHost;

                this.serverPort = serverPort;

                this.group = new MultithreadEventLoopGroup();

                this.bootstrap = new Bootstrap();

                this.bootstrap
                    .Group(this.group)

                    .Channel<TcpSocketChannel>()

                    .Option(ChannelOption.TcpNodelay, true)

                    .Handler(new ActionChannelInitializer<ISocketChannel>(channel =>
                    {
                        IChannelPipeline pipeline = channel.Pipeline;

                        pipeline.AddLast(new LoggingHandler());

                        pipeline.AddLast("idleStateHandler", new IdleStateHandler(0, 10, 0));

                        pipeline.AddLast("framing-enc", new LengthFieldPrepender(4));

                        pipeline.AddLast("framing-dec", new LengthFieldBasedFrameDecoder(int.MaxValue, 0, 4, 0, 4));

                        pipeline.AddLast("AutoUpdate", new ClientHandler(this));

                    }));

                this.connectToServer();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }

        public void connectToServer()
        {
            new Task(new Action(() =>
            {
                Form1.frmMain.changeNetworkStatus(AutoUpdate.Model.Enum.NetworkStatusEnum.Connecting);

                System.Threading.Thread.Sleep(3000);

                connectToServer0();
            })).Start();
        }

        public async void connectToServer0()
        {

            try
            {
                if (this.clientChannel != null)

                    if (this.clientChannel.Active)

                        return;

                Console.WriteLine("try connect to server ..." + this.connectRetry.ToString());

                this.clientChannel = await this.bootstrap.ConnectAsync(new IPEndPoint(IPAddress.Parse(this.serverHost), this.serverPort));

                this.connectRetry = 3;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());

                //this.connectRetry--;

                if (this.connectRetry > 0)
                {
                    System.Threading.Thread.Sleep(3000);

                    this.connectToServer0();
                }

            }
        }

        public async void disconnectAsync()
        {
            await this.clientChannel.CloseAsync();

            await this.group.ShutdownGracefullyAsync(TimeSpan.FromMilliseconds(100), TimeSpan.FromSeconds(1));


        }

        public bool status()
        {
            if (this.clientChannel != null)
                return this.clientChannel.Active;
            else
                return false;
        }



        public void sendMessage(IChannelHandlerContext context, byte[] message)
        {
            try
            {
                IByteBuffer buffer = Unpooled.Buffer(ushort.MaxValue);
                buffer.WriteBytes(message);
                context.WriteAndFlushAsync(buffer);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }

        }

        public bool IsWritable
        {
            get
            {
                return this.clientChannel.IsWritable;
            }
        }
        public void sendMessage(string message)
        {
            this.sendMessage(Encoding.UTF8.GetBytes(message));

        }
        public void sendMessage(byte[] message)
        {

            Console.WriteLine("send");

            if (this.clientChannel.IsWritable)
            {
                Console.WriteLine("can write");
            }
            try
            {
                IByteBuffer buffer = Unpooled.Buffer(ushort.MaxValue);

                buffer.WriteBytes(message);

                this.clientChannel.WriteAndFlushAsync(buffer);

            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }

        }
    }
}
